package com.example.java_gobang.game;

import com.example.java_gobang.JavaGobangApplication;
import com.example.java_gobang.mapper.UserMapper;
import com.example.java_gobang.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

//这个类表示一个游戏房间
@Data
@Slf4j
public class Room {
    //用String方便生成唯一值
    private String roomId;

    private User user1;
    private User user2;

    //哪个玩家是先手方，即先手方的玩家ID
    private int WhiteUser;

    //二维数组表示棋盘
    // 约定
    // 使用0表示当前位置未落子，初始化好的int二维数组就是全0
    // 使用1表示玩家1的落子
    // 使用2表示玩家2的落子
    private int[][] board = new int[15][15];

    private ObjectMapper objectMapper = new ObjectMapper();

    //@Autowired
    private OnlineUserManager onlineUserManager;

    //@Autowired
    private RoomManager roomManager;

    private UserMapper userMapper;

    public Room(){
        // 构造Room的时候生成唯一的字符串表示房间id
        // 使用UUID作为房间id
        roomId = UUID.randomUUID().toString();
        onlineUserManager = (OnlineUserManager) JavaGobangApplication.context.getBean(OnlineUserManager.class);
        roomManager = (RoomManager) JavaGobangApplication.context.getBean(RoomManager.class);
        userMapper = (UserMapper) JavaGobangApplication.context.getBean(UserMapper.class);
    }

    // 通过这个方法来处理一次落子操作
    // 要做的事情：
    // 1.记录当前落子的位置
    // 2.进行胜负判定
    // 3.给客户端返回响应
    public void putChess(String jsonString) throws IOException {
        GameRequest request = objectMapper.readValue(jsonString, GameRequest.class);
        GameResponse response = new GameResponse();
        //1.记录当前落子位置
        int chess = request.getUserId() == user1.getUserId() ? 1 : 2;
        int row = request.getRow();
        int col = request.getCol();
        if(board[row][col] != 0){
            log.info("当前位置已经有子了");
            return;
        }
        board[row][col] = chess;
        //打印当前棋盘信息
//        printBoard();
        int winner = checkWinner(row, col, chess);
        //给房间中的所有客户端返回响应
        response.setMessage("putChess");
        response.setUserId(request.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);
        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(user2.getUserId());
        if(session1 == null){
            //玩家一下线，即调用了GameAPI中的close
            //认为玩家2获胜
            response.setWinner(user2.getUserId());
            log.info("玩家1掉线");
        }
        if(session2 == null){
            response.setWinner(user1.getUserId());
            log.info("玩家2掉线");
        }
        if(session1 != null){
            session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
        if(session2 != null){
            session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
        if(response.getWinner() != 0){
            //胜负已分
            //销毁房间
            roomManager.remove(roomId);
            //更新玩家信息
            userMapper.userWin(response.getWinner());
            userMapper.userLose(response.getWinner() == user1.getUserId() ? user2.getUserId() : user1.getUserId());
        }
    }

    private void printBoard() {
        //打印出棋盘
        System.out.println("打印棋盘信息 " + "房间号：" + roomId);
        System.out.println("==============================================");
        for(int r = 0; r < 15; r++){
            for(int c = 0; c < 15; c++){
                System.out.print(board[r][c] + " ");
            }
            System.out.println();
        }
        System.out.println("==============================================");
    }


    //判定胜负
    //如果玩家1获胜，就返回玩家1的userid
    //如果玩家2获胜，就返回玩家2的userid
    //胜负未分，就返回0
    private int checkWinner(int row, int col, int chess) {
        //行检查
        int size = 0;
        for(int i = Math.max(col - 4, 0); i <= Math.min(col + 4, 14); i++){
            if(board[row][i] == chess)
                size++;
            else
                size = 0;
            if(size == 5)
                return chess == 1 ? user1.getUserId() : user2.getUserId();
        }
        //列检查
        size = 0;
        for(int i = Math.max(row - 4, 0); i <= Math.min(row + 4, 14); i++){
            if(board[i][col] == chess)
                size++;
            else
                size = 0;
            if(size == 5)
                return chess == 1 ? user1.getUserId() : user2.getUserId();
        }
        //主对角线检查(左上到右下)
        size = 0;
        for(int offset = -Math.min(Math.min(row, col), 4); offset <= Math.min(14 - Math.max(row, col), 4); offset++){
            if(board[row + offset][col + offset] == chess)
                size++;
            else
                size = 0;
            if(size == 5)
                return chess == 1 ? user1.getUserId() : user2.getUserId();
        }
        //副对角线检查
        size = 0;
        for(int offset = -Math.min(Math.min(14 - row, col), 4); offset <= Math.min(Math.min(row, 14 - col), 4); offset++){
            if(board[row - offset][col + offset] == chess)
                size++;
            else
                size = 0;
            if(size == 5)
                return chess == 1 ? user1.getUserId() : user2.getUserId();
        }
        return 0;
    }
}
